/******************************************************************************
 * @file     system_tc32l010.c
 * @brief    CMSIS Device System Source File for
 *           tc32l010 Device
 * @version  V1.0.0
 * @date     01. July 2021
 ******************************************************************************/
/*
 * Copyright (c) 2023 CHIPAT Limited. All rights reserved.
 */

#include "tc32l010.h"
#include "tc32l010_gpio.h"
#include "tc32l010_pwr.h"

/**
 * @}
 */

/** @addtogroup XS32L010_System_Private_TypesDefinitions
 * @{
 */

/**
 * @}
 */

/** @addtogroup XS32L010_System_Private_Defines
 * @{
 */
/************************* Miscellaneous Configuration ************************/
//#define HSE_ON

/*!< Uncomment the following line if you need to relocate your vector Table in
     Internal SRAM. */
//#define VECT_TAB_SRAM
#define VECT_TAB_OFFSET 0x00U /*!< Vector Table base offset field. \
                                  This value must be a multiple of 0x100. */

/**
 * @}
 */

/*----------------------------------------------------------------------------
  Define clocks
 *----------------------------------------------------------------------------*/
uint32_t SystemCoreClock = 24000000;
/*----------------------------------------------------------------------------
  System Core Clock Variable
 *----------------------------------------------------------------------------*/

/**
 * @brief  Configures the System clock frequency, AHB/APBx prescalers and Flash
 *         settings.
 * @note   This function should be called only once the RCC clock configuration
 *         is reset to the default reset state (done in SystemInit() function).
 * @param  None
 * @retval None
 */
static void SetSysClock(void)
{
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    __IO uint32_t TmpReg;

#ifdef HSE_ON
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStruct.GPIO_Drive = GPIO_Drive_0;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
    /* Enable HSE */
    RCC->CSR |= ((uint32_t)RCC_CSR_HSEON);

    /* Set HSE Drive */
    RCC->CSR &= ~RCC_CSR_HSEDRV;
    RCC->CSR |= 7 << 13;

    /* Wait till HSE is ready and if Time out is reached exit */
    do
    {
        HSEStatus = RCC->CSR & RCC_CSR_HSERDY;
        StartUpCounter++;
    } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
#endif

    if ((RCC->CSR & RCC_CSR_HSERDY) != RESET)
    {
        HSEStatus = (uint32_t)0x01;
    }
    else
    {
        HSEStatus = (uint32_t)0x00;
        
        /* Set flash Latency before Set HSI range, also need care hsi trimming */
        RCC_SetHSIRange(RCC_HSIRANGE_24MHZ);

        if ((RCC->CSR & 0x0C) == RCC_CSR_HSIRANGE_24)
        {
            RCC_SET_TrimValue(RCC_SELECT_HSI_24M);
        }
        else
        {
            RCC_SET_TrimValue(RCC_SELECT_HSI_4M);
        }
    }

    TmpReg = RCC->CFGR;

    TmpReg &= ~(RCC_CFGR_HPRE | RCC_CFGR_PPRE);

    /* HCLK = SYSCLK */
    TmpReg |= (uint32_t)RCC_CFGR_HPRE_DIV1;

    /* PCLK1 = HCLK / 2 */
    TmpReg |= (uint32_t)RCC_CFGR_PPRE_DIV1;

    RCC->CFGR = TmpReg;

    /* Select system clock source */
    if (HSEStatus == (uint32_t)0x01)
    {
        TmpReg = RCC->CFGR;
        TmpReg &= ~RCC_CFGR_SW;
        RCC->CFGR = TmpReg | RCC_CFGR_SW_HSE;
    }
    else
    { /* If HSE fails to start-up, the application will have wrong clock
               configuration. User can add here some code to deal with this error */
        TmpReg = RCC->CFGR;
        TmpReg &= ~RCC_CFGR_SW;
        RCC->CFGR = TmpReg | RCC_CFGR_SW_HSI;
    }
}

/**
 * @}
 */

/*----------------------------------------------------------------------------
  System Core Clock update function
 *----------------------------------------------------------------------------*/
void SystemCoreClockUpdate(void)
{
    uint32_t tmp = 0;
    uint8_t presc = 0;
    uint32_t HSI_VALUE;
	
    /* Get SYSCLK source -------------------------------------------------------*/
    tmp = RCC->CFGR & RCC_CFGR_SW;

    if (RCC->CSR & RCC_CSR_HSIRANGE_24)
    {
        HSI_VALUE = HSI_VALUE_H;
    }
    else
    {
        HSI_VALUE = HSI_VALUE_L;
    }

    switch (tmp)
    {
    case 0x00: /* HSI used as system clock */
        SystemCoreClock = HSI_VALUE;
        break;
    case 0x01: /* HSE used as system clock */
        SystemCoreClock = HSE_VALUE;
        break;
    case 0x02: /* LSI used as system clock */
        SystemCoreClock = LSI_VALUE;
        break;
    default: /* HSI used as system clock */
        SystemCoreClock = HSI_VALUE;
        break;
    }
    /* Compute HCLK, PCLK clocks frequencies -----------------------------------*/
    /* Get HCLK prescaler */
    tmp = RCC->CFGR & RCC_CFGR_HPRE;
    tmp = tmp >> 4;
    presc = tmp;
    /* HCLK clock frequency */
    SystemCoreClock >>= presc;
}

/*----------------------------------------------------------------------------
  System Parameter initialization function
 *----------------------------------------------------------------------------*/
void SystemParameterInit(void)
{
    PWR_SET_LDOTrimValue(PWR_MLDO_1V2);

    PWR_SET_LDOTrimValue(PWR_ULPLDO_1V2);

    PWR_SET_LDOTrimValue(PWR_MLDO_0V9);

    PWR_SET_LDOTrimValue(PWR_ULPLDO_0V9);

    PWR_SET_LDOTrimValue(PWR_VREF_1V2);

    PWR_SET_LDOTrimValue(PWR_VREF_0V7);
}

/*----------------------------------------------------------------------------
  System initialization function
 *----------------------------------------------------------------------------*/
void SystemInit(void)
{
    /* Set HSION bit */
    RCC->CSR |= (uint32_t)0x00000001;

    /* Set lsi iop singal */
    RCC->LCSCR |= (uint32_t)0x00002000;

    /* Reset SW[1:0], HPRE[2:0], PPRE[1:0], LPUARTSEL, LPTIMSEL, ADCPOL, ADCPRE, MCOSEL[2:0], MCOEN add MCOPRE[1:0] bits */
    RCC->CFGR = 0x00000000;

    /* Reset HSEON, CSSON  bits */
    RCC->CSR &= (uint32_t)0x0000CC8B;

    /* Disable all interrupts */
    RCC->PERIRSTR = 0x00000000;

    SystemParameterInit();

    /* Configure the System clock source, PLL Multiplier and Divider factors,
       AHB/APBx prescalers and Flash settings ----------------------------------*/
    SetSysClock();

    /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}
